home *** CD-ROM | disk | FTP | other *** search
- Subject: v20i060: User-level interface to Ethernet, Part03/03
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Alexander Dupuy <dupuy@cs.columbia.edu>
- Posting-number: Volume 20, Issue 60
- Archive-name: etherlib/part03
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 3 (of 3)."
- # Contents: ./ether.3n ./src/nit3open.c ./src/nit4open.c ./tests/ctp.c
- # ./tests/ethertest.c
- # Wrapped by rsalz@papaya.bbn.com on Wed Oct 25 16:37:32 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f './ether.3n' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./ether.3n'\"
- else
- echo shar: Extracting \"'./ether.3n'\" \(7564 characters\)
- sed "s/^X//" >'./ether.3n' <<'END_OF_FILE'
- X.TH ETHER 3N "29 June 1989"
- X.SH NAME
- Xether \- raw ethernet access functions
- X.SH SYNOPSIS
- X.LP
- X.B #include <ether.h>
- X.LP
- X.nf
- X.ft B
- Xtypedef union etheraddr {
- X char bytes[6];
- X char shorts[3];
- X} ether_addr;
- X
- Xextern ether_addr ether_bcast_addr;
- X
- Xtypedef struct etherpacket {
- X ether_addr dest;
- X ether_addr src;
- X char type[2];
- X unsigned short pktlen;
- X char \(**pktbuf;
- X} ether_packet;
- X
- Xtypedef struct ethervec {
- X ether_addr dest;
- X ether_addr src;
- X char type[2];
- X unsigned short iovcnt;
- X struct iovec \(**iov;
- X} ether_vec;
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xint ether_open(name, type, address)
- Xchar \(**name;
- Xint type;
- Xether_addr \(**address;
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xchar \(**\(**ether_interfaces();
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xether_addr \(**ether_address(fd, address)
- Xint fd;
- Xether_addr \(**address;
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xether_addr \(**ether_intfaddr(name, address)
- Xchar \(**name;
- Xether_addr \(**address;
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xint ether_write(fd, packet)
- Xint fd;
- Xether_packet \(**packet;
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xint ether_read(fd, packet)
- Xint fd;
- Xether_packet \(**packet;
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xint ether_blocking(fd, state)
- Xint fd;
- Xint state;
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xint ether_send_self(fd)
- Xint fd;
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xint ether_mcast_self(fd)
- Xint fd;
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xint ether_bcast_self(fd)
- Xint fd;
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- X#include <sys/types.h>
- X#include <sys/uio.h>
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xint ether_writev(fd, packetvec)
- Xint fd;
- Xether_vec \(**packetvec;
- X.ft R
- X.fi
- X.LP
- X.nf
- X.ft B
- Xint ether_readv(fd, packetvec)
- Xint fd;
- Xether_vec \(**packetvec;
- X.ft R
- X.fi
- X.SH DESCRIPTION
- X.LP
- XThese functions provide access to the raw ethernet for user-level programs. On
- XSuns, they are implemented using
- X.BR \s-1NIT\s0 (4p)
- X(network interface tap). While they do not provide the full
- Xfunctionality of
- X.SM NIT
- X, these functions do run on both the socket- and streams-based
- X.SM NIT
- Ximplementations. On Ultrix systems, they are implemented using
- X.SM DLI
- X(data link interface). On 4.3 BSD systems, they are implemented using the
- XStanford enetfilter device driver in the user-contributed software. These
- Xfunctions are not designed to be used for ethernet monitoring, but rather for
- Xprograms implementing ethernet protocols such as
- X.SM RARP
- X, or the Ethernet configuration test protocol.
- X.LP
- XThe function ether_open returns a file descriptor for the ethernet device
- Xspecified by
- X.I name
- X(such as "le0" or "ie1"). If no name is given, the default ethernet interface
- Xis used. Packets for the ethernet address
- X.I address
- Xwill be received in addition to packets for the local ethernet address and
- Xbroadcasts; this is useful for multicast protocols. Superuser privilege is
- Xneeded to use this feature. Only packets with a protocol type of
- X.I type
- Xwill be received or sent. This value should be passed in host byte order, not
- Xin network byte order.
- X.LP
- XIn order to allow some basic ethernet monitoring capability on Sun
- X.SM NIT
- X-based systems and BSD enetfilter systems, if
- X.I address
- Xis all zeros, or if
- X.I type
- Xis ETHER_ALLTYPES (defined in ether.h), address and/or type matching will be
- Xdisabled. This will not work on Ultrix
- X.SM DLI
- X-based systems, so using the
- X.SM NIT
- Xinterface directly is nearly as portable, and gives better filtering and
- Xbuffering.
- X.LP
- XThe ether_interfaces function can be used to determine the valid interface
- Xnames available. It returns an array of strings (with the last element set to
- X\s-1NULL\s0), each entry of which is an ethernet interface name valid for use
- Xin ether_open.
- X.LP
- XThe ether_address function returns the local ethernet address for the ethernet
- Xinterface on the file descriptor
- X.IR fd .
- XThe result is stored in the structure given by
- X.IR address ;
- Xif none is given,
- X.IR malloc (3)
- Xis used to allocate space.
- X.LP
- XThe ether_read and ether_write functions read or write a single ethernet
- Xpacket. When writing, the
- X.IR dest ,
- X.I pktlen
- Xand
- X.I pktbuf
- Xfields must be provided; the
- X.I src
- Xand
- X.I type
- Xfields are set to the local ethernet address and the ethernet type passed
- Xto
- X.IR ether_open (\|).
- XWhen reading, only
- X.I pktlen
- Xand
- X.I pktbuf
- Xare looked at; the
- X.IR src ,
- X.IR dest ,
- Xand
- X.I type
- Xfields are set from the packet on a successful return. If
- X.I pktbuf
- Xis non-\s-1NULL\s0, up to
- X.I pktlen
- Xbytes will be read in to the buffer space specified by
- X.IR pktbuf .
- XIf
- X.I pktbuf
- Xis \s-1NULL\s0,
- X.I pktlen
- Xis ignored and
- X.IR malloc (3)
- Xis used to allocate enough space for the packet. The value of
- X.I pktlen
- Xis set to the lesser of its original value and the actual packet size
- X(exclusive of the ethernet header). The size of the original ethernet packet
- Xis returned.
- X.LP
- XThe ether_readv and ether_writev functions operate in the same way as
- Xether_read and ether_write, but use an interface like that provided by the
- Xreadv and writev system calls. The
- X.I iov
- Xand
- X.I iovcnt
- Xfields specify the length and location of an array of struct iovec. Each iovec
- Xentry specifies the base address and length of an area in memory where data is
- Xread from or written to.
- X.LP
- XThe ether_blocking function can be used to make the ethernet file descriptor
- X.I fd
- Xnon-blocking. If
- X.I state
- Xis zero, the file descriptor is set non-blocking with
- X.IR fcntl (2);
- Xif
- X.I state
- Xis non-zero, the file descriptor is set to be blocking.
- X.LP
- XThe ether_send_self, ether_mcast_self and ether_bcast_self functions return 1
- Xif the interface will receive packets that it sends to itself, multicasts or
- Xbroadcasts, respectively, and will return 0 if the interface will not receive
- Xsuch packets.
- X.LP
- XIn addition, there are a number of auxiliary routines for manipulating ethernet
- Xaddresses. Although they are not documented here, the ether.h header file
- Xdescribes them.
- X.SH DIAGNOSTICS
- XAll functions which return an integer value return a negative number if there
- Xis an error. A zero return indicates no error. The ether_interfaces and
- Xether_addresses functions return \s-1NULL\s0 if there is an error. All
- Xfunctions leave an error code in the external variable
- X.I errno
- Xif an error occurs. If an attempt to read an ethernet file descriptor which
- Xhas been set to non-blocking mode fails because the operation would block,
- Xerrno will be set to EAGAIN (not EWOULDBLOCK).
- X.SH BUGS
- XDoesn't support IEEE 802.3 based protocols.
- X.LP
- XBecause of restrictions in the
- X.SM DLI
- Xand socket based
- X.SM NIT
- Ximplementations, the ether_open function may require superuser privilege on
- Xsome machines. On SunOS 4.0 machines, it is sufficient to be able to open
- Xthe /dev/nit special file. On machines with the Stanford enetfilter, it is
- Xsufficient to be able to open the interface's special file in /dev/enet/.
- X.LP
- XDue to limitations in the Stanford enetfilter, using select to determine if
- Xan ethernet device is ready to accept writes will always return true. Also,
- Xusing ether_blocking(0) will not prevent blocking on writes. Since writes
- Xalmost always complete quickly, this isn't a major problem, but applications
- Xmay block if the ethernet is jammed.
- X.LP
- XThe basic monitoring capabilities provided are a hack. Something like
- X.SM NIT
- Xshould be standardized as a monitoring interface.
- X.LP
- XThe auxiliary address routines should be better documented.
- X.SH SEE ALSO
- X.BR nit (4p),
- X.BR nit_if (4p),
- X.BR nit_pf (4p),
- X.BR enet (4),
- X.BR fcntl (2),
- X.BR fcntl (5)
- X.SH AUTHORS
- XAlexander Dupuy, Robert Mokry, Columbia University Computer Science Department.
- XThanks to Charlie Kim for ideas stolen from his ethernet access implementation.
- XSome of the auxiliary ethernet address routines are derived from code written
- Xby Philip Budne, Boston University Computer Science Department.
- END_OF_FILE
- if test 7564 -ne `wc -c <'./ether.3n'`; then
- echo shar: \"'./ether.3n'\" unpacked with wrong size!
- fi
- # end of './ether.3n'
- fi
- if test -f './src/nit3open.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./src/nit3open.c'\"
- else
- echo shar: Extracting \"'./src/nit3open.c'\" \(6958 characters\)
- sed "s/^X//" >'./src/nit3open.c' <<'END_OF_FILE'
- X/* $Id: nit3open.c,v 2.2 89/10/24 17:53:27 dupuy Exp $ */
- X
- X#include <sys/param.h> /* NOFILE */
- X#include <sys/time.h> /* timeval */
- X#include <sys/socket.h> /* sockaddr_nit (sockaddr) */
- X#include <sys/ioctl.h> /* ioctl */
- X
- X#include <net/nit.h> /* sockaddr_nit */
- X#include <netinet/in.h> /* htons */
- X
- X#include <strings.h> /* strncpy */
- X#include <errno.h> /* EWOULDBLOCK/EINVAL */
- X
- X#include "libether.h"
- X
- Xstruct timeval *ether_timeout;
- Xstruct timeval *ether_timestamp;
- X
- Xstatic ether_addr promiscuous;
- X
- Xstatic fd_set multicast;
- Xstatic gotlocal;
- Xstatic ether_addr local_addr;
- X
- Xunsigned _ether_types[NOFILE];
- Xether_addr _ether_multi_addrs[NOFILE];
- X
- X#define ether_type (_ether_types[fd])
- X#define multi_addr (_ether_multi_addrs[fd])
- X
- X/*
- X * Returns file descriptor for ethernet device by name ("ie0", "le0", etc.).
- X * If name is NULL, uses primary ethernet interface. Will only receive
- X * packets of type specified. Will receive packets for the ethernet address
- X * specified, or local ethernet address if NULL. If there is an error,
- X * returns (-1) and the appropriate value is left in errno. Normal return
- X * status zero. Requires superuser privilege.
- X */
- X
- Xint
- Xether_open (name, type, address)
- Xchar *name;
- Xunsigned type;
- Xether_addr *address;
- X{
- X int fd;
- X struct sockaddr_nit snit;
- X struct nit_ioc nioc;
- X char **interfaces;
- X int saved_errno;
- X
- X if (name == 0)
- X { /* get default ethernet interface */
- X interfaces = ether_interfaces ();
- X if (interfaces == 0 || *interfaces == 0)
- X return (-1);
- X
- X name = *interfaces; /* just use the first name in list */
- X }
- X
- X if ((fd = socket (AF_NIT, SOCK_RAW, NITPROTO_RAW)) < 0)
- X {
- X#ifdef DEBUG
- X perror ("ether_open: socket");
- X#endif
- X return (-1);
- X }
- X
- X snit.snit_family = AF_NIT;
- X (void) strncpy (snit.snit_ifname, name, NITIFSIZ);
- X
- X if (bind (fd, (struct sockaddr *) &snit, sizeof (snit)) != 0)
- X {
- X saved_errno = errno;
- X#ifdef DEBUG
- X perror ("ether_open: bind");
- X#endif
- X (void) close (fd);
- X errno = saved_errno;
- X return (-1);
- X }
- X
- X bzero ((char *) &nioc, sizeof (nioc));
- X
- X if (type != ETHER_ALLTYPES && type > ETHER_MAXTYPE)
- X {
- X (void) close (fd);
- X errno = EINVAL;
- X return (-1);
- X }
- X
- X nioc.nioc_bufalign = sizeof (long);
- X nioc.nioc_chunksize = nioc.nioc_bufspace = ETHER_BUFSIZ;
- X nioc.nioc_typetomatch =
- X (type == ETHER_ALLTYPES) ? type : htons ((u_short) type);
- X nioc.nioc_snaplen = ETHER_PKT + ETHER_MAX;
- X
- X if (address == 0) /* not a multicast address */
- X {
- X multicast.fds_bits[0] &= ~(1 << fd);
- X nioc.nioc_flags = NF_TIMEOUT;
- X }
- X else /* a multicast address */
- X {
- X if (ether_cmp (address, &promiscuous))
- X {
- X if (!ETHER_MCAST (address))
- X {
- X#ifdef DEBUG
- X (void) printf ("rejecting non-multicast address argument\n");
- X#endif
- X (void) close (fd);
- X errno = EINVAL;
- X return (-1);
- X }
- X
- X multicast.fds_bits[0] |= (1 << fd);
- X multi_addr = *address;
- X if (gotlocal == 0)
- X if (ether_address (fd, &local_addr) != NULL)
- X gotlocal = 1;
- X }
- X else
- X multicast.fds_bits[0] &= ~(1 << fd);
- X
- X nioc.nioc_flags = NF_TIMEOUT | NF_PROMISC;
- X }
- X
- X if (ether_timeout != 0) /* use specified value of timeout */
- X nioc.nioc_timeout = *ether_timeout;
- X else
- X { /* then use default value of timeout */
- X nioc.nioc_timeout.tv_sec = 0;
- X nioc.nioc_timeout.tv_usec = 10000;
- X }
- X
- X if (ioctl (fd, SIOCSNIT, (char *) &nioc) != 0)
- X {
- X saved_errno = errno;
- X#ifdef DEBUG
- X perror ("ether_open: ioctl SIOCSNIT");
- X#endif
- X (void) close (fd);
- X errno = saved_errno;
- X return (-1);
- X }
- X
- X ether_type = type;
- X return (fd);
- X}
- X
- X
- X#ifdef DEBUG
- X
- Xvoid
- Xdump_nit_hdr (nitbuf)
- Xstruct nit_hdr *nitbuf;
- X{
- X switch (nitbuf->nh_state)
- X {
- X case NIT_QUIET:
- X (void) printf ("ether_read: nit quiet\n");
- X break;
- X
- X case NIT_CATCH:
- X (void) printf ("ether_read: nit catch: size %d\n", nitbuf->nh_datalen);
- X break;
- X
- X case NIT_NOMBUF:
- X (void) printf ("ether_read: nit no mbufs: %d lost\n",
- X nitbuf->nh_dropped);
- X break;
- X
- X case NIT_NOCLUSTER:
- X (void) printf ("ether_read: nit no mclusters: %d lost\n",
- X nitbuf->nh_dropped);
- X break;
- X
- X case NIT_NOSPACE:
- X (void) printf ("ether_read: nit no bufspace: %d lost\n",
- X nitbuf->nh_dropped);
- X break;
- X
- X case NIT_SEQNO:
- X (void) printf ("ether_read: nit sequence # %d\n", nitbuf->nh_seqno);
- X break;
- X
- X default:
- X (void) printf ("ether_read: bad nit header state: %d\n",
- X nitbuf->nh_state);
- X break;
- X }
- X}
- X
- X#endif
- X
- X
- X/*
- X * Reads and returns a single packet, filling in all fields. If pktbuf is
- X * NULL, a buffer is allocated for it. If pktbuf is not NULL, the function
- X * assumes that pktbuf is large enough to hold pktlen bytes. Since read() may
- X * return several packets at a time, ether_read() has to buffer them as well.
- X * Since socket based nit doesn't handle multicast addresses, we have to check
- X * them at the user level.
- X *
- X * NOTE - the buffering code is non-reentrant if the same fd is used.
- X */
- X
- Xstatic long ether_buf[NOFILE][ETHER_BUFSIZ / sizeof (long)];
- Xstatic int ether_buflen[NOFILE];
- Xstatic char *ether_bufptr[NOFILE];
- X
- X#define buf (ether_buf[fd])
- X#define buflen (ether_buflen[fd])
- X#define bufptr (ether_bufptr[fd])
- X
- X_ether_next_packet (fd, bufp)
- Xint fd;
- Xchar **bufp;
- X{
- X struct nit_hdr *nitbuf;
- X ether_addr *pbuf;
- X
- X if (bufptr == 0) /* easier than static initialization */
- X bufptr = (char *) buf;
- X
- X for (;;)
- X {
- X if ((bufptr - (char *) buf) >= buflen)
- X { /* then buffer is used up */
- X buflen = read (fd, (char *) buf, ETHER_BUFSIZ);
- X bufptr = (char *) buf;
- X if (buflen <= 0)
- X {
- X if (errno == EWOULDBLOCK)
- X errno = EAGAIN;
- X return (-1);
- X }
- X }
- X
- X /*
- X * This assignment is safe, since nit guarantees requested alignment
- X */
- X
- X nitbuf = (struct nit_hdr *) bufptr;
- X while (nitbuf->nh_state != NIT_CATCH)
- X {
- X#ifdef DEBUG
- X dump_nit_hdr (nitbuf);
- X#endif
- X nitbuf++;
- X if ((char *) nitbuf - (char *) buf > buflen)
- X {
- X#ifdef DEBUG
- X (void) printf ("truncated nit_hdr struct in buffer\n");
- X#endif
- X continue;
- X }
- X }
- X#ifdef DEBUG
- X dump_nit_hdr (nitbuf);
- X#endif
- X /*
- X * Set bufptr to next nit_hdr, pbuf to start of ether packet
- X */
- X
- X bufptr = ((char *) (pbuf = (ether_addr *) (nitbuf + 1)))
- X + nitbuf->nh_datalen + pad (nitbuf->nh_datalen);
- X
- X /*
- X * Check for local, broadcast or multicast packet
- X */
- X
- X if ((multicast.fds_bits[0] & (1 << fd))
- X && (ETHER_MCAST (pbuf) ? (ether_cmp (pbuf, ðer_bcast_addr)
- X && ether_cmp (pbuf, &multi_addr))
- X : ether_cmp (pbuf, &local_addr)))
- X {
- X#ifdef DEBUG
- X (void) printf ("discarding incorrectly addressed packet\n");
- X#endif
- X continue;
- X }
- X
- X if (nitbuf->nh_wirelen > nitbuf->nh_datalen)
- X {
- X#ifdef DEBUG
- X (void) printf ("discarding truncated packet\n");
- X#endif
- X continue;
- X }
- X break;
- X }
- X
- X if (nitbuf->nh_wirelen - ETHER_PKT < 0)
- X errno = EBADMSG;
- X else
- X *bufp = (char *) pbuf;
- X
- X ether_timestamp = &nitbuf->nh_timestamp;
- X
- X return (nitbuf->nh_wirelen - ETHER_PKT);
- X}
- END_OF_FILE
- if test 6958 -ne `wc -c <'./src/nit3open.c'`; then
- echo shar: \"'./src/nit3open.c'\" unpacked with wrong size!
- fi
- # end of './src/nit3open.c'
- fi
- if test -f './src/nit4open.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./src/nit4open.c'\"
- else
- echo shar: Extracting \"'./src/nit4open.c'\" \(5614 characters\)
- sed "s/^X//" >'./src/nit4open.c' <<'END_OF_FILE'
- X/* $Id: nit4open.c,v 2.1 89/10/23 15:42:59 dupuy Exp $ */
- X
- X#include <sys/file.h> /* O_RDWR */
- X#include <sys/stropts.h> /* RMSGD */
- X#include <sys/types.h> /* NIOCBIND (u_long) */
- X#include <sys/time.h> /* NIOCBIND (timeval) */
- X#include <sys/socket.h> /* ifreq (sockaddr) */
- X
- X#include <net/if.h> /* ifreq */
- X#include <net/nit_if.h> /* NIOCBIND */
- X#include <net/nit_pf.h> /* NIOCSETF */
- X#include <net/packetfilt.h> /* packetfilt */
- X
- X#include <netinet/in.h> /* htons */
- X
- X#include <strings.h> /* strncpy */
- X#include <errno.h> /* EMFILE/EINVAL */
- X
- X#include "libether.h"
- X
- X#ifndef NIT_DEV
- X#define NIT_DEV "/dev/nit"
- X#endif
- X
- Xstatic ether_addr promiscuous;
- X
- Xunsigned _ether_types[FD_SETSIZE];
- X
- X#define ether_type (_ether_types[fd])
- X
- Xstatic int
- Xnioctl (fd, cmd, ptr)
- Xint fd;
- Xint cmd;
- Xchar *ptr;
- X{
- X int saved_errno;
- X
- X if (ioctl (fd, cmd, ptr) < 0)
- X {
- X saved_errno = errno;
- X#ifdef DEBUG
- X switch (cmd)
- X {
- X case I_SRDOPT:
- X perror ("ether_open: ioctl (I_SRDOPT)");
- X break;
- X case I_PUSH:
- X perror ("ether_open: ioctl (I_PUSH)");
- X break;
- X case NIOCSETF:
- X perror ("ether_open: ioctl (NIOCSETF)");
- X break;
- X case NIOCBIND:
- X perror ("ether_open: ioctl (NIOCBIND)");
- X break;
- X case NIOCSFLAGS:
- X perror ("ether_open: ioctl (NIOCSFLAGS)");
- X break;
- X default:
- X perror ("ether_open: ioctl (????)");
- X break;
- X }
- X#endif
- X (void) close (fd);
- X errno = saved_errno;
- X return (-1);
- X }
- X
- X return (0);
- X}
- X
- X
- X/*
- X * Returns file descriptor for ethernet device by name ("ie0", "le0", etc.).
- X * If name is NULL, uses primary ethernet interface. Will only receive
- X * packets of type specified. Will receive packets for the ethernet address
- X * specified, or local ethernet address if NULL. If there is an error,
- X * returns (-1) and the appropriate value is left in errno. Normal return
- X * status zero. Requires superuser privilege.
- X */
- X
- Xint
- Xether_open (name, type, address)
- Xchar *name;
- Xunsigned type;
- Xether_addr *address;
- X{
- X int fd;
- X struct ifreq ifr;
- X struct packetfilt filter;
- X unsigned short *fptr = 0;
- X char **interfaces;
- X register int i;
- X
- X if (name == 0) /* get default ethernet interface */
- X {
- X interfaces = ether_interfaces ();
- X if (interfaces == 0 || *interfaces == 0)
- X return (-1);
- X
- X name = *interfaces; /* just use the first name in list */
- X }
- X
- X if ((fd = open (NIT_DEV, O_RDWR)) < 0)
- X {
- X#ifdef DEBUG
- X perror (NIT_DEV);
- X#endif
- X return (-1);
- X }
- X
- X if (fd >= FD_SETSIZE) /* not worth making it work here */
- X {
- X (void) close (fd);
- X errno = EMFILE;
- X return (-1);
- X }
- X
- X /* arrange to get discrete messages from the stream */
- X
- X if (nioctl (fd, I_SRDOPT, (char *) RMSGD) < 0)
- X return (-1);
- X
- X /* set up filter */
- X
- X if (type != ETHER_ALLTYPES) /* hack for NIT features */
- X {
- X if (type > ETHER_MAXTYPE)
- X {
- X (void) close (fd);
- X errno = EINVAL;
- X return (-1);
- X }
- X
- X if (nioctl (fd, I_PUSH, "pf") < 0)
- X return (-1);
- X
- X fptr = &filter.Pf_Filter[0];
- X
- X *fptr++ = ENF_PUSHWORD + ETHER_TYPE / sizeof (short);
- X *fptr++ = ENF_PUSHLIT | ENF_EQ;
- X *fptr++ = htons ((u_short) type);
- X
- X filter.Pf_FilterLen = fptr - &filter.Pf_Filter[0];
- X filter.Pf_Priority = 1; /* unimportant, so long as < 2 */
- X
- X if (nioctl (fd, NIOCSETF, (char *) &filter) < 0)
- X return (-1);
- X }
- X
- X /*
- X * We defer the bind until after we've pushed the filter to prevent our
- X * being flooded with extraneous packets
- X */
- X
- X (void) strncpy (ifr.ifr_name, name, sizeof (ifr.ifr_name));
- X
- X if (nioctl (fd, NIOCBIND, (char *) &ifr) < 0)
- X return (-1);
- X
- X if (address != 0)
- X {
- X if (ether_cmp (address, &promiscuous))
- X {
- X#ifndef MULTICAST
- X ether_addr local_addr;
- X#endif
- X if (!ETHER_MCAST (address))
- X {
- X#ifdef DEBUG
- X (void) printf ("rejecting non-multicast address argument\n");
- X#endif
- X (void) close (fd);
- X errno = EINVAL;
- X return (-1);
- X }
- X
- X#ifdef MULTICAST
- X /* #error not clear how to set multicast addresses */
- X exit (-1); /* die die die */
- X#else
- X
- X /*
- X * Enable address matching filter before we go into promiscuous
- X * mode. We have to do this after the bind, since we can't get
- X * the interface address until then.
- X */
- X
- X (void) ether_address (fd, &local_addr);
- X
- X /* may not have pushed packet filtering module yet */
- X
- X if (fptr == 0)
- X if (nioctl (fd, I_PUSH, "pf") < 0)
- X return (-1);
- X
- X fptr = &filter.Pf_Filter[0];
- X
- X if (type != ETHER_ALLTYPES) /* hack for NIT features */
- X {
- X *fptr++ = ENF_PUSHWORD + ETHER_TYPE / sizeof (short);
- X *fptr++ = ENF_PUSHLIT;
- X *fptr++ = htons ((u_short) type);
- X *fptr++ = ENF_CAND;
- X }
- X
- X for (i = 0; i < 3; i++) /* compare addresses in 3 shorts */
- X {
- X *fptr++ = ENF_PUSHWORD + ETHER_DST / sizeof (short) + i;
- X *fptr++ = ENF_PUSHLIT | ENF_EQ;
- X *fptr++ = address->shorts[i];
- X *fptr++ = ENF_PUSHWORD + ETHER_DST / sizeof (short) + i;
- X *fptr++ = ENF_PUSHLIT | ENF_EQ;
- X *fptr++ = ether_bcast_addr.shorts[i];
- X *fptr++ = ENF_OR;
- X *fptr++ = ENF_PUSHWORD + ETHER_DST / sizeof (short) + i;
- X *fptr++ = ENF_PUSHLIT | ENF_EQ;
- X *fptr++ = local_addr.shorts[i];
- X *fptr++ = ENF_CNOR;
- X }
- X
- X filter.Pf_FilterLen = fptr - &filter.Pf_Filter[0];
- X filter.Pf_Priority = 1; /* unimportant, so long as < 2 */
- X
- X if (nioctl (fd, NIOCSETF, (char *) &filter) < 0)
- X return (-1);
- X
- X#endif /* MULTICAST */
- X
- X }
- X
- X#ifdef MULTICAST
- X else /* only promiscuous if requested */
- X#endif
- X
- X { /* go into promiscuous mode */
- X long flag;
- X
- X flag = NI_PROMISC;
- X
- X if (nioctl (fd, NIOCSFLAGS, (char *) &flag) < 0)
- X return (-1);
- X }
- X }
- X
- X ether_type = type;
- X return (fd);
- X}
- END_OF_FILE
- if test 5614 -ne `wc -c <'./src/nit4open.c'`; then
- echo shar: \"'./src/nit4open.c'\" unpacked with wrong size!
- fi
- # end of './src/nit4open.c'
- fi
- if test -f './tests/ctp.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./tests/ctp.c'\"
- else
- echo shar: Extracting \"'./tests/ctp.c'\" \(14485 characters\)
- sed "s/^X//" >'./tests/ctp.c' <<'END_OF_FILE'
- X/* $Id: ctp.c,v 1.3 89/10/24 17:54:23 dupuy Exp $ */
- X
- X/*
- X * ctp - ethernet configuration test protocol program
- X */
- X
- X/*
- X * derived from ethertools/ctp.c
- X *
- X * Copyright (c) 1988 Philip L. Budne and The Trustees of Boston University All
- X * Rights Reserved
- X *
- X * Permission is granted to any individual or institution to use, copy, or
- X * redistribute this software so long as it is not sold for profit, provided
- X * that this notice and the original copyright notices are retained. Boston
- X * University makes no representations about the suitability of this software
- X * for any purpose. It is provided "as is" without express or implied
- X * warranty.
- X */
- X
- X#include <stdio.h>
- X#include <signal.h>
- X#include <errno.h>
- X
- Xextern int errno;
- X
- X#include "ctp.h"
- X
- X#ifdef SIGABRT
- X#define sigtype void
- X#else
- X#define sigtype int
- X#endif
- X
- Xstruct timeval *ether_timestamp; /* timestamp from 3.x NIT, maybe */
- X
- X/*
- X * Ethernet related variables
- X */
- X
- Xint nomulticast = 0;
- X
- X#ifdef __STDC__
- Xether_addr ctpmulticast = {{0xcf, 0x0, 0x0, 0x0, 0x0, 0x0}};
- X
- X#else
- Xether_addr ctpmulticast;
- Xunsigned char bytes[6] = {0xcf, 0x0, 0x0, 0x0, 0x0, 0x0};
- X
- X#endif
- X
- Xether_addr localaddr; /* our ethernet address */
- X
- X/*
- X * CTP statistics
- X */
- X
- X#define NBUCKETS 733 /* prime # of buckets */
- X#define hash(addr) \
- X (((addr)->shorts[1] + ((addr)->shorts[1] ^ (addr)->shorts[2])) % NBUCKETS)
- X
- Xint nsent = 0;
- X
- Xstruct
- X{
- X int nrecvd; /* total count */
- X int highseq; /* highest seq seen */
- X int outofseq; /* number recvd out of sequence */
- X int min;
- X int max; /* min and max times */
- X int sum; /* sum of times */
- X
- X int valid; /* is this a used entry */
- X ether_addr eaddr; /* ethernet address for this count */
- X}
- X stats[NBUCKETS + 1];
- X
- Xint lastseq = 0;
- Xint seq = 0;
- X
- X/*
- X * Program options and arguments
- X */
- X
- Xchar *interface = NULL; /* interface to use */
- Xint count = -1; /* number of packets to send */
- Xint noreturn = 0; /* don't force final forward back */
- Xint packlen = ETHER_MIN; /* default total packet length */
- Xint slptim = 1000; /* sleep time in ms */
- X
- X/*
- X * Other functions and variables
- X */
- X
- Xint pid; /* our pid */
- Xint tosend = 0;
- X
- Xshort swaps ();
- Xsigtype resend ();
- Xsigtype die ();
- Xvoid printstats ();
- Xctp_reply *output_packet ();
- Xvoid input_packet ();
- X
- X
- Xmain (argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X int efd;
- X int optind;
- X ether_addr path[MAXPATH];
- X int pathcount = 0;
- X ether_packet outpkt;
- X ctp_packet outpktbuf;
- X ctp_reply *reply; /* pointer to ctp_reply in outpkt */
- X struct itimerval interval;
- X
- X /*
- X * Get program options
- X */
- X
- X if ((optind = getoptions (argc, argv)) < 0 || optind >= argc)
- X {
- X (void) fprintf (stderr,
- X "Usage: %s [-c count] [-n] [-i intf] [-l len] [-s sleep] addr ...\n",
- X argv[0]);
- X exit (1);
- X }
- X
- X /*
- X * Open ethernet interface
- X */
- X
- X if (interface == NULL)
- X {
- X char **intfs;
- X
- X if ((intfs = ether_interfaces ()) == NULL)
- X {
- X perror ("ether_interfaces");
- X exit (1);
- X }
- X
- X interface = *intfs;
- X }
- X
- X#ifndef __STDC__
- X (void) bcopy ((char *) bytes, (char *) ctpmulticast.bytes, sizeof (bytes));
- X#endif
- X
- X if ((efd = ether_open (interface, CTPTYPE, &ctpmulticast)) < 0)
- X {
- X /* try again w/o multicast, for enetfilter systems */
- X
- X nomulticast++;
- X
- X if ((efd = ether_open (interface, CTPTYPE, (ether_addr *) 0)) < 0)
- X {
- X perror (interface);
- X exit (1);
- X }
- X }
- X
- X /*
- X * Set non-blocking, so that we can select and loop
- X */
- X
- X if (ether_blocking (efd, 0) != 0)
- X {
- X perror ("ether_block");
- X exit (1);
- X }
- X
- X /*
- X * Get local interface address and process id
- X */
- X
- X if (ether_address (efd, &localaddr) == NULL)
- X {
- X perror ("ether_address");
- X exit (1);
- X }
- X
- X (void) printf ("%s address %s\n", interface, ether_ntoa (&localaddr));
- X
- X pid = getpid (); /* so we can identify our packets */
- X
- X /*
- X * Set up forwarding path for CTP packet
- X */
- X
- X pathcount = 0;
- X while (optind < argc && pathcount < MAXPATH && argv[optind] != NULL)
- X {
- X if (strcmp (argv[optind], "MULTICAST") == 0)
- X path[pathcount] = ctpmulticast;
- X
- X else if (strcmp (argv[optind], "BROADCAST") == 0)
- X path[pathcount] = ether_bcast_addr;
- X
- X else if (!ether_host2e (argv[optind], &path[pathcount]))
- X {
- X extern char *sys_errlist[];
- X int saved_errno = errno;
- X
- X (void) puts ("");
- X (void) fflush (stdout);
- X if (errno == ENOENT)
- X (void) fprintf (stderr, "%s: unknown host %s\n",
- X argv[0], argv[optind]);
- X else
- X (void) fprintf (stderr, "%s: can't get address for %s: %s\n",
- X argv[0], argv[optind],
- X sys_errlist[saved_errno]);
- X
- X exit (1);
- X }
- X
- X (void) printf ("%s%s (%s)", ((pathcount > 0) ? "\n " : "CTP "),
- X argv[optind], ether_ntoa (&path[pathcount]));
- X
- X pathcount++;
- X optind++;
- X }
- X
- X if (pathcount == MAXPATH)
- X {
- X fputs (": ", stdout);
- X (void) fflush (stdout);
- X (void) fprintf (stderr, "Too many hosts in path (%d)\n", MAXPATH);
- X exit (1);
- X }
- X
- X /*
- X * Build output packet
- X */
- X
- X reply = output_packet (efd, &outpkt, &outpktbuf, path, pathcount);
- X
- X /*
- X * Set up signal handlers and timers
- X */
- X
- X (void) signal (SIGALRM, resend);
- X (void) signal (SIGINT, die);
- X (void) signal (SIGHUP, die);
- X (void) signal (SIGTERM, die);
- X
- X interval.it_interval.tv_sec = slptim / 1000;
- X interval.it_interval.tv_usec = slptim % 1000;
- X interval.it_value.tv_sec = slptim / 1000;
- X interval.it_value.tv_usec = slptim % 1000;
- X
- X if (setitimer (ITIMER_REAL, &interval, (struct itimerval *) 0) < 0)
- X {
- X perror ("setitimer");
- X exit (1);
- X }
- X
- X /*
- X * Loop checking for packets
- X */
- X
- X while (count != 0)
- X {
- X fd_set fdset;
- X
- X if (tosend > 0)
- X {
- X tosend--;
- X
- X reply->seq = seq++;
- X
- X /*
- X * It's safe to cast reply->sendt, since that will be long aligned
- X */
- X
- X (void) gettimeofday ((struct timeval *) reply->sendt,
- X (struct timezone *) 0);
- X
- X if (ether_write (efd, &outpkt) < 0)
- X {
- X perror ("ether_read");
- X exit (1);
- X }
- X
- X nsent++;
- X count--;
- X }
- X
- X FD_ZERO (&fdset);
- X FD_SET (efd, &fdset);
- X
- X while (tosend == 0)
- X {
- X ether_packet pkt;
- X ctp_packet pktbuf;
- X struct timeval tv;
- X
- X pkt.pktbuf = (char *) &pktbuf;
- X pkt.pktlen = sizeof (pktbuf);
- X
- X if (select (efd + 1, param (&fdset), param (0), param (0),
- X (struct timeval *) 0) < 0)
- X {
- X if (errno == EINTR)
- X break; /* from while loop */
- X
- X perror ("select");
- X exit (1);
- X }
- X
- X for (;;) /* while packets can be read */
- X {
- X if (ether_read (efd, &pkt) < 0)
- X {
- X if (errno == EAGAIN)
- X break; /* from for loop */
- X
- X perror ("ether_read");
- X exit (1);
- X }
- X
- X /*
- X * Use 3.x NIT timestamp if present, since latency is terrible
- X */
- X
- X if (ether_timestamp)
- X tv = *ether_timestamp;
- X else
- X (void) gettimeofday (&tv, (struct timezone *) 0);
- X
- X input_packet (&pkt, &pktbuf, &tv);
- X }
- X }
- X }
- X
- X printstats ();
- X exit (0);
- X}
- X
- Xctp_reply *
- Xoutput_packet (efd, pkt, ctp, path, pathcount)
- Xint efd;
- Xether_packet *pkt;
- Xctp_packet *ctp;
- Xether_addr path[];
- Xint pathcount;
- X{
- X ctp_forward *forward;
- X ctp_reply *reply;
- X int i;
- X
- X ctp->skip = 0;
- X
- X /*
- X * Since ctp is long aligned, and the data offset is 2, we are safe
- X */
- X
- X forward = (ctp_forward *) ctp->data;
- X for (i = 1; i < pathcount; i++)
- X {
- X forward->function = swaps (CTP_FWD);
- X forward->addr = path[i];
- X forward++;
- X }
- X
- X /* ensure packet gets back -- append forward to ourselves if needed */
- X
- X if (!noreturn && ether_cmp (&path[pathcount - 1], &localaddr)
- X && (ether_cmp (&path[pathcount - 1], ðer_bcast_addr)
- X || !ether_bcast_self (efd) || pathcount == 1
- X || ether_cmp (&path[pathcount - 2], &localaddr))
- X && (nomulticast || ether_cmp (&path[pathcount - 1], &ctpmulticast)
- X || !ether_mcast_self (efd) || pathcount == 1
- X || ether_cmp (&path[pathcount - 2], &localaddr)))
- X {
- X forward->function = swaps (CTP_FWD);
- X forward->addr = localaddr;
- X forward++;
- X }
- X
- X reply = (ctp_reply *) forward;
- X
- X i = ((char *) (reply + 1)) - (char *) ctp;
- X
- X if (i > packlen)
- X if (i > ETHER_MAX)
- X {
- X (void) fputs (": ", stdout);
- X (void) fflush (stdout);
- X (void) fprintf (stderr, "Packet too large without data (%d)\n", i);
- X exit (1);
- X }
- X else
- X packlen = i;
- X
- X (void) printf (": %d data bytes (%d total)\n", packlen - i, packlen + 14);
- X (void) fflush (stdout);
- X
- X reply->function = swaps (CTP_REP); /* create reply data */
- X reply->pid = pid;
- X
- X pkt->dest = path[0]; /* fill in ether packet header */
- X pkt->pktbuf = (char *) ctp;
- X pkt->pktlen = packlen;
- X
- X return (reply); /* return pointer to reply struct */
- X}
- X
- X
- Xsigtype
- Xresend ()
- X{
- X tosend++;
- X}
- X
- Xsigtype
- Xdie ()
- X{
- X puts ("");
- X printstats ();
- X exit (0);
- X}
- X
- Xvoid
- Xprintstats ()
- X{
- X int bucket = 0;
- X int lastbucket = -1;
- X int min = ((unsigned) -1) >> 1;
- X int max = -1;
- X int nrecvd = 0;
- X int sum = 0;
- X
- X (void) printf ("----CTP Statistics----\n");
- X (void) printf ("%d packet%s transmitted", nsent,
- X (nsent == 1 ? "" : "s"));
- X
- X for (;;)
- X {
- X while (stats[bucket].valid == 0 && bucket < NBUCKETS)
- X bucket++;
- X
- X if (lastbucket != -1
- X && (bucket != NBUCKETS || stats[lastbucket].nrecvd != nrecvd))
- X {
- X char hostaddr[ETHERSTRLEN];
- X char host[MAXHOSTNAMELEN];
- X
- X (void) ether_e2a (&stats[lastbucket].eaddr, hostaddr);
- X
- X (void) printf ("\n %d received from ", stats[lastbucket].nrecvd);
- X
- X if (ether_e2host (&stats[lastbucket].eaddr, host) == NULL)
- X (void) fputs (hostaddr, stdout);
- X else
- X (void) printf ("%s (%s)", host, hostaddr);
- X
- X if (nsent - stats[lastbucket].nrecvd < 0)
- X (void) puts ("");
- X else
- X (void) printf (", %d%% packet loss\n", 100 *
- X (nsent - stats[lastbucket].nrecvd) / nsent);
- X if (stats[lastbucket].nrecvd > 0)
- X (void)
- X printf (" round-trip (ms) min/avg/max = %d/%d/%d",
- X stats[lastbucket].min,
- X stats[lastbucket].sum / stats[lastbucket].nrecvd,
- X stats[lastbucket].max);
- X }
- X
- X if (bucket == NBUCKETS)
- X break; /* done with loop */
- X
- X lastbucket = bucket;
- X
- X if (min > stats[bucket].min)
- X min = stats[bucket].min;
- X if (max < stats[bucket].max)
- X max = stats[bucket].max;
- X
- X nrecvd += stats[bucket].nrecvd;
- X sum += stats[bucket].sum;
- X
- X bucket++;
- X }
- X
- X if (lastbucket == -1 || stats[lastbucket].nrecvd == nrecvd)
- X {
- X (void) printf (", %d received", nrecvd);
- X
- X if (nsent - nrecvd < 0)
- X (void) puts ("");
- X else
- X (void) printf (", %d%% packet loss\n",
- X 100 * (nsent - nrecvd) / nsent);
- X }
- X else
- X fputs ("\noverall ", stdout);
- X
- X if (nrecvd > 0)
- X (void) printf ("round-trip (ms) min/avg/max = %d/%d/%d\n",
- X min, sum / nrecvd, max);
- X}
- X
- Xvoid
- Xinput_packet (pkt, ctp, tv)
- Xether_packet *pkt;
- Xctp_packet *ctp;
- Xstruct timeval *tv;
- X{
- X short skip;
- X ctp_reply *reply;
- X int ms;
- X int bucket;
- X
- X skip = swaps (ctp->skip); /* fetch skip */
- X
- X if (skip & 1) /* if skip is odd, we are unaligned */
- X return;
- X
- X /*
- X * Since ctp is long aligned, and skip is not odd, this is safe
- X */
- X
- X reply = (ctp_reply *) &ctp->data[skip];
- X
- X if (pkt->pktlen - skip - 2 < 2) /* no room for function */
- X return;
- X
- X switch (swaps (reply->function))
- X {
- X case CTP_REP: /* reply */
- X break;
- X
- X case CTP_FWD: /* XXX - should really process this */
- X return;
- X
- X default: /* probably a byteswapped function */
- X return;
- X }
- X
- X if (pkt->pktlen - skip - 2 < sizeof (ctp_reply))
- X return;
- X
- X if (reply->pid != pid) /* not our packet */
- X return;
- X
- X (void) printf ("%d bytes from %s: seq=%d time=", pkt->pktlen + ETHER_PKT,
- X ether_ntoa (&pkt->src), reply->seq);
- X
- X /*
- X * It's safe to cast reply->sendt, since that will be long aligned
- X */
- X
- X if ((ms = delta (tv, (struct timeval *) reply->sendt)) < 0)
- X {
- X (void) printf ("(%d ms)!!!\n", ms);
- X ms = 0; /* time must have jumped back, yuck */
- X }
- X else
- X (void) printf ("%d ms\n", ms);
- X
- X (void) fflush (stdout);
- X
- X bucket = hash (&pkt->src);
- X
- X while (stats[bucket].valid && ether_cmp (&stats[bucket].eaddr, &pkt->src))
- X if (++bucket >= NBUCKETS)
- X bucket = 0;
- X
- X if (!stats[bucket].valid) /* initialize new bucket */
- X {
- X stats[bucket].nrecvd = 0;
- X stats[bucket].highseq = 0;
- X stats[bucket].outofseq = 0;
- X stats[bucket].min = ((unsigned) -1) >> 1;
- X stats[bucket].max = -1;
- X stats[bucket].sum = 0;
- X stats[bucket].valid = 1;
- X stats[bucket].eaddr = pkt->src;
- X }
- X
- X stats[bucket].nrecvd++;
- X
- X if (reply->seq != lastseq && reply->seq != lastseq + 1)
- X stats[bucket].outofseq++;
- X lastseq = reply->seq;
- X if (reply->seq > stats[bucket].highseq)
- X stats[bucket].highseq = reply->seq;
- X
- X if (ms > stats[bucket].max)
- X stats[bucket].max = ms;
- X if (ms < stats[bucket].min)
- X stats[bucket].min = ms;
- X stats[bucket].sum += ms;
- X}
- X
- Xdelta (a, b)
- Xstruct timeval *a;
- Xstruct timeval *b;
- X{
- X long usec;
- X long sec;
- X
- X usec = a->tv_usec - b->tv_usec;
- X sec = a->tv_sec - b->tv_sec;
- X
- X if (usec < 0)
- X {
- X sec--;
- X usec += 1000000;
- X }
- X
- X usec += 500; /* round to ms */
- X sec = sec * 1000 + usec / 1000; /* get ms */
- X
- X return (sec);
- X} /* delta */
- X
- X
- Xgetoptions (argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X extern char *optarg;
- X extern int optind;
- X int opt;
- X int errs;
- X
- X errs = 0;
- X while ((opt = getopt (argc, argv, "c:i:l:ns:")) != EOF)
- X {
- X switch (opt)
- X {
- X case 'c':
- X if ((count = atoi (optarg)) <= 0)
- X {
- X errs++;
- X (void) fprintf (stderr, "invalid packet count: %s\n", optarg);
- X }
- X break;
- X
- X case 'i':
- X interface = optarg;
- X break;
- X
- X case 'l':
- X if ((packlen = atoi (optarg)) <= 0)
- X {
- X errs++;
- X (void) fprintf (stderr, "invalid packet length: %s\n", optarg);
- X }
- X else if (packlen < ETHER_MIN)
- X {
- X (void) fprintf (stderr,
- X "packet length %s increased to minimum %d\n",
- X optarg, ETHER_MIN);
- X packlen = ETHER_MIN;
- X }
- X else if (packlen > ETHER_MAX)
- X {
- X (void) fprintf (stderr,
- X "packet length %s decreased to maximum %d\n",
- X optarg, ETHER_MAX);
- X packlen = ETHER_MAX;
- X }
- X break;
- X
- X case 'n':
- X noreturn ^= 1;
- X break;
- X
- X case 's':
- X slptim = atoi (optarg);
- X break;
- X
- X default:
- X errs++;
- X }
- X }
- X
- X if (errs)
- X return (-1);
- X else
- X return (optind);
- X}
- X
- X
- Xshort
- Xswaps (word)
- Xunsigned short word;
- X{
- X static int swap = -1;
- X
- X if (swap < 0)
- X {
- X short test = 0x0100;
- X swap = *(char *) &test;
- X }
- X
- X if (swap)
- X return (word >> 8 | (word & 0xff) << 8);
- X else
- X return (word);
- X}
- END_OF_FILE
- if test 14485 -ne `wc -c <'./tests/ctp.c'`; then
- echo shar: \"'./tests/ctp.c'\" unpacked with wrong size!
- fi
- # end of './tests/ctp.c'
- fi
- if test -f './tests/ethertest.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'./tests/ethertest.c'\"
- else
- echo shar: Extracting \"'./tests/ethertest.c'\" \(9445 characters\)
- sed "s/^X//" >'./tests/ethertest.c' <<'END_OF_FILE'
- X/* $Id: ethertest.c,v 1.3 89/10/24 17:54:39 dupuy Exp $ */
- X
- X#include <stdio.h>
- X#include <strings.h> /* strcmp */
- X
- X#include <sys/param.h> /* MAXHOSTNAMELEN */
- X#include <sys/uio.h> /* iov */
- X#include <sys/socket.h>
- X
- X#include <errno.h> /* EAGAIN */
- X#include <netdb.h> /* hostent */
- X
- X#include <netinet/in.h> /* in_addr */
- X
- X#include "ether.h"
- X
- X#if defined(lint) && defined (ultrix)
- Xvoid bcopy ();
- Xvoid perror ();
- Xvoid exit ();
- Xunsigned sleep ();
- X#endif
- X
- X#if !defined (sun) && !defined (ultrix)
- Xextern uid_t getuid ();
- X#endif
- X
- X#define offsetof(type,mem) ((unsigned) &(((type *) 0)->mem))
- X
- Xchar hello[] = "hello,";
- Xchar world[] = " world";
- Xstruct iovec iov[2] = {{hello, 6}, {world, 7}};
- Xchar helloworld[] = "hello, world";
- Xstruct iovec iov2[1] = {{helloworld, 13}};
- X
- X#ifdef __STDC__
- Xether_addr multicast = {{ 0x0f, 0x0f, 0x0f, 0xfe, 0xfe, 0x00 }};
- X#else
- Xether_addr multicast;
- Xunsigned char bytes[6] = { 0x0f, 0x0f, 0x0f, 0xfe, 0xfe, 0x00 };
- X#endif
- Xchar mcastname1[] = "0f:0F:f:Fe:fE:0";
- Xchar mcastname2[] = "0f-0F-f-Fe-fE-0";
- X
- Xether_vec packetv;
- Xether_packet packet;
- X
- Xchar *inet_n2a ();
- X
- Xextern int errno;
- X
- Xmain ()
- X{
- X char hostname[MAXHOSTNAMELEN + 1];
- X char *hname = NULL;
- X struct hostent *hdata;
- X ether_addr eaddress;
- X ether_addr eaddress2;
- X ether_addr eaddress3;
- X char **intfs;
- X int uid;
- X int i = ETHER_SRC;
- X
- X /*
- X * Initialize union
- X */
- X
- X#ifndef __STDC__
- X (void) bcopy ((char *) bytes, (char *) multicast.bytes, sizeof (bytes));
- X#endif
- X
- X /*
- X * Test some structures for compiler sanity
- X */
- X
- X if (i != sizeof (ether_addr))
- X (void) fprintf (stderr, "WARNING!!! sizeof (ether_addr) = %d\n",
- X sizeof (ether_addr));
- X if (ETHER_PKT != offsetof (ether_packet, type[2]))
- X (void) fprintf (stderr, "WARNING!!! offset of ether_packet = %d\n",
- X offsetof (ether_packet, type[2]));
- X
- X#ifdef __GNUC__
- X (void) printf ("ether_addr alignment = %d, ether_packet alignment = %d\n",
- X __alignof (ether_addr), __alignof (ether_packet));
- X#endif
- X
- X /*
- X * Get the canonical hostname
- X */
- X
- X if (gethostname (hostname, sizeof (hostname)) < 0)
- X perror ("gethostname");
- X else
- X {
- X hname = hostname;
- X
- X if ((hdata = gethostbyname (hostname)) == 0)
- X (void) fprintf (stderr, "host info for %s not found\n", hostname);
- X else
- X {
- X hname = hdata->h_name;
- X
- X if ((hdata = gethostbyaddr (hdata->h_addr, hdata->h_length,
- X hdata->h_addrtype)) == 0)
- X (void) fprintf (stderr, "%s address does not match\n", hname);
- X else
- X hname = hdata->h_name;
- X
- X }
- X }
- X
- X if (hname)
- X (void) printf ("%s ethertest\n", hname);
- X
- X /*
- X * Get the ethernet interface names and test some utility functions
- X */
- X
- X if ((intfs = ether_interfaces ()) == NULL)
- X {
- X perror ("ether_interfaces");
- X exit (1);
- X }
- X
- X if (hname)
- X {
- X if (ether_host2e (hostname, &eaddress) == NULL)
- X (void) fprintf (stderr, "ether_h2e failed\n");
- X else
- X (void) printf ("%s: %s\n", hostname, ether_ntoa (&eaddress));
- X }
- X
- X if (hdata)
- X {
- X struct in_addr ipaddr;
- X
- X (void) bcopy (hdata->h_addr, (char *) &ipaddr, sizeof (ipaddr));
- X if (ether_hostent2e (hdata, &eaddress2) == NULL)
- X (void) fprintf (stderr, "ether_he2e failed\n");
- X
- X else if (bcmp ((char *) &eaddress, (char *) &eaddress2,
- X sizeof (ether_addr)))
- X (void) printf ("%s: %s\n", hdata->h_name, ether_ntoa (&eaddress2));
- X
- X if (ether_ip2e (&ipaddr, &eaddress3) == NULL)
- X perror ("ether_ip2e");
- X
- X else if (bcmp ((char *) &eaddress3, (char *) &eaddress2,
- X sizeof (ether_addr)))
- X (void) printf ("%s: %s\n", inet_n2a (ipaddr),
- X ether_ntoa (&eaddress3));
- X }
- X
- X uid = getuid ();
- X
- X /*
- X * Loop through the interfaces, testing functions
- X */
- X
- X for (i = 0; intfs[i]; i++)
- X {
- X ether_addr address;
- X int fd;
- X int self;
- X
- X (void) printf ("%s: ", intfs[i]);
- X (void) fflush (stdout);
- X
- X if ((fd = ether_open (intfs[i], 0xf0f0, (ether_addr *) NULL)) < 0)
- X perror ("open");
- X else
- X {
- X struct in_addr ipaddr;
- X char hostname2[MAXHOSTNAMELEN + 1];
- X
- X (void) setreuid (0, uid);
- X
- X if (ether_address (fd, &address) == NULL)
- X perror ("address");
- X else
- X (void) printf ("%s\n", ether_ntoa (&address));
- X
- X hostname2[MAXHOSTNAMELEN] = '\0';
- X if (ether_e2host (&address, hostname2) == NULL)
- X {
- X (void) fprintf (stderr, "ether_e2host failed\n");
- X if (ether_e2ip (&address, &ipaddr) == NULL)
- X (void) fprintf (stderr, "ether_e2ip failed\n");
- X }
- X else
- X {
- X if (ether_e2ip (&address, &ipaddr) == NULL)
- X (void) fprintf (stderr, "ether_e2ip failed\n");
- X else
- X (void) printf ("%s: %s\n", hostname2, inet_n2a (ipaddr));
- X }
- X
- X self = ether_bcast_self (fd);
- X
- X packet.pktbuf = "dlrow ,olleh";
- X packet.pktlen = 13;
- X bcopy ((char *) ðer_bcast_addr, (char *) &packet.dest,
- X sizeof (address));
- X if (ether_write (fd, &packet) < 0)
- X perror ("ether_write");
- X
- X if (ether_blocking (fd, 0))
- X perror ("ether_blocking");
- X
- X (void) sleep (1);
- X
- X packetv.iov = iov2;
- X packetv.iovcnt = sizeof (iov2) / sizeof (struct iovec);
- X
- X if (ether_readv (fd, &packetv) < 0)
- X {
- X if (errno != EAGAIN)
- X perror ("ether_readv");
- X else if (self == 0)
- X (void)
- X (void) printf ("%s",
- X "interface cannot receive own broadcasts\n");
- X else
- X (void) fprintf (stderr, "%s %s\n",
- X "interface cannot receive own broadcasts",
- X "but thinks that it can!");
- X }
- X else if (strcmp (helloworld, "dlrow ,olleh"))
- X (void) fprintf (stderr,
- X "bcast_self test received garbled packet\n");
- X
- X else if (bcmp ((char *) &packetv.src, (char *) &address,
- X sizeof (ether_addr)))
- X (void) fprintf (stderr, "WARNING: source address %s!\n",
- X ether_e2a (&packetv.src, (char *) 0));
- X else if (self == 1)
- X {
- X (void) printf ("%s",
- X "interface will receive own broadcasts\n");
- X }
- X else
- X {
- X (void) fprintf (stderr, "%s %s\n",
- X "interface will receive own broadcasts",
- X "but doesn't think that it can!");
- X }
- X
- X self = ether_send_self (fd);
- X
- X packetv.iov = iov;
- X packetv.iovcnt = sizeof (iov) / sizeof (struct iovec);
- X
- X bcopy ((char *) &address, (char *) &packetv.dest, sizeof (address));
- X if (ether_writev (fd, &packetv) < 0)
- X perror ("ether_writev");
- X
- X (void) sleep (1);
- X
- X packet.pktbuf = NULL;
- X if (ether_read (fd, &packet) < 0)
- X {
- X if (errno != EAGAIN)
- X perror ("ether_read");
- X else if (self == 0)
- X (void) printf ("%s",
- X "interface cannot send packets to self\n");
- X else
- X (void) fprintf (stderr, "%s %s\n",
- X "interface cannot send packets to self",
- X "but thinks that it can!");
- X }
- X else if (strcmp (packet.pktbuf, "hello, world"))
- X (void) fprintf (stderr,
- X "send_self test received garbled packet\n");
- X
- X else if (!bcmp ((char *) &packetv.src, (char *) &address,
- X sizeof (ether_addr)))
- X (void) fprintf (stderr, "WARNING: source address %s!\n",
- X ether_ntoa (&packetv.src));
- X
- X else if (self == 1)
- X {
- X (void) printf ("%s", "interface can send packets to self\n");
- X }
- X else
- X {
- X (void) fprintf (stderr, "%s %s\n",
- X "interface can send packets to self",
- X "but doesn't think that it can!");
- X }
- X
- X (void) close (fd);
- X
- X (void) setreuid (uid, 0);
- X
- X if ((fd = ether_open (intfs[i], 0xf0f0, &multicast)) < 0)
- X (void) printf (
- X "interface does not support multicast reception\n");
- X else
- X {
- X (void) setreuid (0, uid);
- X
- X self = ether_mcast_self (fd);
- X
- X packet.pktbuf = "dlrow ,olleh";
- X packet.pktlen = 13;
- X bcopy ((char *) &multicast, (char *) &packet.dest,
- X sizeof (address));
- X if (ether_write (fd, &packet) < 0)
- X perror ("ether_write");
- X
- X if (ether_blocking (fd, 0))
- X perror ("ether_blocking");
- X
- X (void) sleep (1);
- X
- X packetv.iov = iov2;
- X packetv.iovcnt = sizeof (iov2) / sizeof (struct iovec);
- X
- X if (ether_readv (fd, &packetv) < 0)
- X {
- X if (errno != EAGAIN)
- X perror ("ether_readv");
- X else if (self == 0)
- X (void)
- X (void) printf ("%s",
- X "interface cannot receive own multicasts\n");
- X else
- X (void) fprintf (stderr, "%s %s\n",
- X "interface cannot receive own multicasts",
- X "but thinks that it can!");
- X }
- X else if (strcmp (helloworld, "dlrow ,olleh"))
- X (void) fprintf (stderr,
- X "mcast_self test received garbled packet\n");
- X
- X else if (bcmp ((char *) &packetv.src, (char *) &address,
- X sizeof (ether_addr)))
- X (void) fprintf (stderr, "WARNING: source address %s!\n",
- X ether_ntoa (&packetv.src));
- X
- X else if (self == 1)
- X {
- X (void) printf ("%s",
- X "interface will receive own multicasts\n");
- X }
- X else
- X {
- X (void) fprintf (stderr, "%s %s\n",
- X "interface will receive own multicasts",
- X "but doesn't think that it can!");
- X }
- X
- X (void) setreuid (uid, 0);
- X }
- X }
- X }
- X
- X if (ether_cmp (&multicast, ether_aton (mcastname1)))
- X (void) fprintf (stderr, "ether_aton failed (%s)\n",
- X ether_ntoa (ether_aton (mcastname1)));
- X
- X if (ether_cmp (&multicast, ether_a2e (mcastname2, &eaddress)))
- X (void) fprintf (stderr, "ether_a2e failed (%s)\n",
- X ether_ntoa (&eaddress));
- X
- X return (0);
- X}
- X
- Xchar *
- Xinet_n2a (addr)
- Xstruct in_addr addr;
- X{
- X#ifdef lint
- X char *sprintf ();
- X#endif
- X static char buffer[16];
- X unsigned char *bytes;
- X
- X bytes = (unsigned char *) &addr;
- X (void) sprintf (buffer, "%d.%d.%d.%d",
- X bytes[0], bytes[1], bytes[2], bytes[3]);
- X
- X return (buffer);
- X}
- END_OF_FILE
- if test 9445 -ne `wc -c <'./tests/ethertest.c'`; then
- echo shar: \"'./tests/ethertest.c'\" unpacked with wrong size!
- fi
- # end of './tests/ethertest.c'
- fi
- echo shar: End of archive 3 \(of 3\).
- cp /dev/null ark3isdone
- MISSING=""
- for I in 1 2 3 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 3 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-